package com.tsfyun.scm.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.tsfyun.common.base.support.CustomLocalDateTimeDeserializer;
import com.tsfyun.common.base.support.DateDeserializer;
import com.tsfyun.common.base.support.StringDeserializer;
import com.tsfyun.scm.security.config.TokenRenewalInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * @Description:
 * @CreateDate: Created in 2021/8/2 15:56
 */
@Slf4j
@AutoConfigureAfter(ObjectMapper.class)
@Configuration
public class CustomWebMvcConfiguration implements WebMvcConfigurer, InitializingBean {

    /**
     * 只能有一个WebMvcConfigurationSuppor；
     * WebMvcConfigurationSuppor和WebMvcConfigurer同时存在，会导致WebMvcConfigurer的拦截器无法执行
     */

    @Autowired(required = false)
    private ObjectMapper objectMapper;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(sqlInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(repeatSubmitInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(tokenRenewalInterceptor()).addPathPatterns("/**");
    }

    /**
     * 租户拦截器
     * @return
     */
    @Bean
    TokenRenewalInterceptor tokenRenewalInterceptor() {
        return new TokenRenewalInterceptor();
    }

    /**
     * SQL注入拦截器
     * @return
     */
    @Bean
    SqlInterceptor sqlInterceptor() {
        return new SqlInterceptor();
    }

    /**
     * 重复提交拦截器
     * @return
     */
    @Bean
    RepeatSubmitInterceptor repeatSubmitInterceptor() {
        return new RepeatSubmitInterceptor();
    }

    /**
     * 静态资源映射
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");

        registry.addResourceHandler("/favicon.ico")
                .addResourceLocations("classpath:/static/");

        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("doc.html").addResourceLocations(
                "classpath:/META-INF/resources/");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (objectMapper != null) {
            objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
            objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
            //空值字段也返回
            //objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

            DateFormat myDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            objectMapper.setDateFormat(myDateFormat);

            JavaTimeModule javaTimeModule = new JavaTimeModule();
            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
            //javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
            objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule());
            /**
             * 序列换成json时,将所有的long变成string
             * 因为js中的数字类型不能包含所有的java long值
             */
            SimpleModule simpleModule = new SimpleModule();
            simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
            simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
            //LocalDateTime默认序列化
            simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            //字符串参数映射去掉前后空格以及特殊符号
            simpleModule.addDeserializer(String.class, StringDeserializer.instance);
            //日期参数映射根据字符串长度自动匹配格式
            simpleModule.addDeserializer(Date.class, DateDeserializer.instance);

            simpleModule.addDeserializer(LocalDateTime.class, CustomLocalDateTimeDeserializer.instance);

            objectMapper.registerModule(simpleModule);
            log.info("jackson转换器初始化完成");
        }
    }
}
